
package fr.inserm.um915.jimpute.model;

public class AllelesResolver
    {

    public static class Resolved
        {
        private String a0;
        private String a1;
        private String message;
        private String flagEndOfLine=null;
    private boolean set_chrom_to_zero=false;
        public void setA0(String a0)
            {
            this.a0 = a0;
            }
        public void setA1(String a1)
            {
            this.a1 = a1;
            }
        public void setMessage(String message)
            {
            this.message = message;
            }
        public String getA0() {
            return a0;
            }
        public String getA1() {
            return a1;
            }
        public String getMessage()
            {
            return message;
            }
        public void setFlagEndOfLine(String flagEndOfLine)
            {
            this.flagEndOfLine = flagEndOfLine;
            }
        public String getFlagEndOfLine()
            {
            return flagEndOfLine;
            }
    public boolean isChromZero()
        {
        return set_chrom_to_zero;
        }
    void setChromZero(boolean b)
        {
        set_chrom_to_zero=b;
        }
        }

    private boolean same(String a0,String a1)
        {
        return a0.equalsIgnoreCase(a1);
        }

    private boolean antiparallele(String a0,String a1)
        {
        return same(a0,antiparallele(a1));
        }

    private String antiparallele(String src)
        {
        StringBuilder b=new StringBuilder(src.length());
        for(int i=src.length()-1;i>=0;--i)
            {
            switch(Character.toUpperCase(src.charAt(i)))
                {
                case 'A': b.append('T'); break;
                case 'T': b.append('A'); break;
                case 'G': b.append('C'); break;
                case 'C': b.append('G'); break;
                case '-': b.append('-'); break;
                case '/': b.append('/'); break;
                case 'N': b.append('N'); break;
                default: b.append(src.charAt(i));break;
                }
            }
        return b.toString();
        }




    public Resolved resolve(
            String userA0,
            String userA1,
            String imputeA0,
            String imputeA1)
        {
        Resolved ret=new Resolved();



    // 2 same user/1000G (examples: A/C A/C or C/A A/C)
    if(same(userA0,imputeA0) && same(userA1,imputeA1) && !antiparallele(userA0,userA1))
        {
        ret.setA0(imputeA0);
        ret.setA1(imputeA1);
        return ret;
        }
    else if(same(userA0,imputeA1) && same(userA1,imputeA0) && !antiparallele(userA0,userA1))
        {
        ret.setA0(userA0);
        ret.setA1(userA1);
        return ret;
        }

    // 2 antiparallele user/1000G (examples: A/C T/G or A/C G/T)
    else if(antiparallele(imputeA0,userA1) && antiparallele(imputeA1,userA0))
        {
        if(antiparallele(userA0,userA1)) //exception : antiparallele user (example: A/T A/T)
            {
            ret.setMessage("found anti-parallele alleles data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+" keeping data");
            ret.setA0(userA0);
            ret.setA1(userA1);
            ret.setFlagEndOfLine("ANTIPARALLELE_CHECK_FREQUENCIES"); // keeping user and check allele frequency
            return ret;
            }
        else{
            ret.setMessage("found anti-parallele alleles. keeping impute reversed data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1);
            ret.setA0(imputeA1);
            ret.setA1(imputeA0);
            ret.setFlagEndOfLine("ANTIPARALLELE");
            return ret;
            }
        }
    else if(antiparallele(imputeA0,userA0) && antiparallele(imputeA1,userA1))
        {
        if(antiparallele(userA0,userA1)) //exception : antiparallele user (example: A/T T/A)
            {
            ret.setMessage("found anti-parallele alleles. keeping impute reversed data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+" keeping data");
            ret.setA0(userA0);
            ret.setA1(userA1);
            ret.setFlagEndOfLine("ANTIPARALLELE_MISORDERED_CHECK_FREQUENCIES"); // keeping user and check allele frequency
            return ret;
            }
        else{
            ret.setMessage("found misordered anti-parallele alleles. keeping impute data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1);
            ret.setA0(imputeA0);
            ret.setA1(imputeA1);
            ret.setFlagEndOfLine("ANTIPARALLELE_MISORDERED");
            return ret;
            }
        }

    // 1 same user/1000G ; 1 antiparallele user/1000G (examples: A/C A/G or C/A A/G or A/C G/A or C/A G/A)
    else if(same(userA0,imputeA0) && antiparallele(userA1,imputeA1) && !same(userA0,userA1))
        {
        ret.setMessage("found one misordered anti-parallele alleles. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+userA0+"/"+imputeA1);
        ret.setA0(userA0);
        ret.setA1(imputeA1);
        ret.setFlagEndOfLine("ONE_SAME_ONE_ANTIPARALLELE");
        return ret;
        }
    else if(same(userA1,imputeA0) && antiparallele(userA0,imputeA1) && !same(userA0,userA1))
        {
        ret.setMessage("found one misordered anti-parallele alleles. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+imputeA1+"/"+userA1);
        ret.setA0(imputeA1);
        ret.setA1(userA1);
        ret.setFlagEndOfLine("ONE_SAME_ONE_ANTIPARALLELE");
        return ret;
        }
    else if(same(userA0,imputeA1) && antiparallele(userA1,imputeA0) && !same(userA0,userA1))
        {
        ret.setMessage("found one misordered anti-parallele alleles. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+userA0+"/"+imputeA0);
        ret.setA0(userA0);
        ret.setA1(imputeA0);
        ret.setFlagEndOfLine("ONE_SAME_ONE_ANTIPARALLELE");
        return ret;
        }
    else if(same(userA1,imputeA1) && antiparallele(userA0,imputeA0) && !same(userA0,userA1))
        {
        ret.setMessage("found one misordered anti-parallele alleles. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+imputeA0+"/"+userA1);
        ret.setA0(imputeA0);
        ret.setA1(userA1);
        ret.setFlagEndOfLine("ONE_SAME_ONE_ANTIPARALLELE");
        return ret;
        }

    // 1 same user/1000G ; 1 different(!antiparallele,!same,!=0,!="-") user/1000G (examples: A/C A/T or C/A A/T or A/C T/A or C/A T/A)
    else if(same(userA0,imputeA0) && (!antiparallele(userA1,imputeA1) && !same(userA1,imputeA1) && !userA1.equals("0") && !userA1.equals("-")))
        {
        ret.setMessage("data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+userA0+"/"+imputeA1);
        ret.setA0(userA0);
        ret.setA1(imputeA1);
        ret.setFlagEndOfLine("ONE_SAME_ONE_DIFFERENT_CHECK_FREQUENCIES");
        return ret;
        }
    else if(same(userA1,imputeA0) && (!antiparallele(userA0,imputeA1) && !same(userA0,imputeA1) && !userA0.equals("0") && !userA0.equals("-")))
        {
        ret.setMessage("data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+imputeA1+"/"+userA1);
        ret.setA0(imputeA1);
        ret.setA1(userA1);
        ret.setFlagEndOfLine("ONE_SAME_ONE_DIFFERENT_CHECK_FREQUENCIES");
        return ret;
        }
    else if(same(userA0,imputeA1) && (!antiparallele(userA1,imputeA0) && !same(userA1,imputeA0) && !userA1.equals("0") && !userA1.equals("-")))
        {
        ret.setMessage("data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+userA0+"/"+imputeA0);
        ret.setA0(userA0);
        ret.setA1(imputeA0);
        ret.setFlagEndOfLine("ONE_SAME_ONE_DIFFERENT_CHECK_FREQUENCIES");
        return ret;
        }
    else if(same(userA1,imputeA1) && (!antiparallele(userA0,imputeA0) && !same(userA0,imputeA0) && !userA0.equals("0") && !userA0.equals("-")))
        {
        ret.setMessage("data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+imputeA0+"/"+userA1);
        ret.setA0(imputeA0);
        ret.setA1(userA1);
        ret.setFlagEndOfLine("ONE_SAME_ONE_DIFFERENT_CHECK_FREQUENCIES");
        return ret;
        }
    // 1 antiparallele user/1000G ; 1 different(!antiparallele,!same,!=0,!="-") user/1000G (examples: A/C G/G or C/A G/G)
    else if(antiparallele(userA1,imputeA1) && (!antiparallele(userA0,imputeA0) && !same(userA0,imputeA0) && !same(userA0,userA1) && !userA0.equals("0") && !userA0.equals("-")))
        {
        ret.setMessage("data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+imputeA0+"/"+imputeA1);
        ret.setA0(imputeA0);
        ret.setA1(imputeA1);
        ret.setFlagEndOfLine("ONE_SAME_ONE_DIFFERENT_CHECK_FREQUENCIES");
        return ret;
        }
    else if(antiparallele(userA0,imputeA0) && (!antiparallele(userA1,imputeA1) && !same(userA1,imputeA1) && !same(userA0,userA1) && !userA1.equals("0") && !userA1.equals("-")))
        {
        ret.setMessage("data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+userA1+"/"+imputeA1);
        ret.setA0(imputeA0);
        ret.setA1(imputeA1);
        ret.setFlagEndOfLine("ONE_SAME_ONE_DIFFERENT_CHECK_FREQUENCIES");
        return ret;
        }
    else if(antiparallele(userA0,imputeA1) && (!antiparallele(userA1,imputeA0) && !same(userA1,imputeA0) && !same(userA0,userA1) && !userA1.equals("0") && !userA1.equals("-")))
        {
        ret.setMessage("data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+imputeA1+"/"+imputeA0);
        ret.setA0(imputeA1);
        ret.setA1(imputeA0);
        ret.setFlagEndOfLine("ONE_SAME_ONE_DIFFERENT_CHECK_FREQUENCIES");
        return ret;
        }
    else if(antiparallele(userA1,imputeA0) && (!antiparallele(userA0,imputeA1) && !same(userA0,imputeA1) && !same(userA0,userA1) && !userA0.equals("0") && !userA0.equals("-")))
        {
        ret.setMessage("data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+imputeA1+"/"+imputeA0);
        ret.setA0(imputeA0);
        ret.setA1(imputeA1);
        ret.setFlagEndOfLine("ONE_SAME_ONE_DIFFERENT_CHECK_FREQUENCIES");
        return ret;
        }

    // 1 same user/1000G ; 1 user 0 (examples: A/0 A/C or A/0 C/A or 0/A A/C or 0/A C/A)
    else if(same(userA0,imputeA0) && userA1.equals("0"))
        {
        ret.setMessage("found one 0-allele. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+userA0+"/"+imputeA1);
        ret.setA0(userA0);
        ret.setA1(imputeA1);
        ret.setFlagEndOfLine("ALLELE_0");
        return ret;
        }
    else if(same(userA0,imputeA1) && userA1.equals("0"))
        {
        ret.setMessage("found one 0-allele. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+userA0+"/"+imputeA0);
        ret.setA0(userA0);
        ret.setA1(imputeA0);
        ret.setFlagEndOfLine("ALLELE_0");
        return ret;
        }
    else if(same(userA1,imputeA0) && userA0.equals("0"))
        {
        ret.setMessage("found one 0-allele. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+imputeA1+"/"+userA1);
        ret.setA0(imputeA1);
        ret.setA1(userA1);
        ret.setFlagEndOfLine("ALLELE_0");
        return ret;
        }
    else if(same(userA1,imputeA1) && userA0.equals("0"))
        {
        ret.setMessage("found one 0-allele. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+imputeA0+"/"+userA1);
        ret.setA0(imputeA0);
        ret.setA1(userA1);
        ret.setFlagEndOfLine("ALLELE_0");
        return ret;
        }

    // 1 antiparallele user/1000G ; 1 user 0 (examples: A/0 T/C or A/0 C/T or 0/A T/C or 0/A C/T)
    else if(antiparallele(userA0,imputeA0) && userA1.equals("0"))
        {
        ret.setMessage("found one 0-allele. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+imputeA0+"/"+imputeA1);
        ret.setA0(imputeA0);
        ret.setA1(imputeA1);
        ret.setFlagEndOfLine("ALLELE_0");
        return ret;
        }
    else if(antiparallele(userA0,imputeA1) && userA1.equals("0"))
        {
        ret.setMessage("found one 0-allele. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+imputeA1+"/"+imputeA0);
        ret.setA0(imputeA1);
        ret.setA1(imputeA0);
        ret.setFlagEndOfLine("ALLELE_0");
        return ret;
        }
    else if(antiparallele(userA1,imputeA0) && userA0.equals("0"))
        {
        ret.setMessage("found one 0-allele. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+imputeA1+"/"+imputeA0);
        ret.setA0(imputeA1);
        ret.setA1(imputeA0);
        ret.setFlagEndOfLine("ALLELE_0");
        return ret;
        }
    else if(antiparallele(userA1,imputeA1) && userA0.equals("0"))
        {
        ret.setMessage("found one 0-allele. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+imputeA0+"/"+imputeA1);
        ret.setA0(imputeA0);
        ret.setA1(imputeA1);
        ret.setFlagEndOfLine("ALLELE_0");
        return ret;
        }

    // indels -/A ou A/- => ATCG/A ou A/ATCG
    // 1 same user/1000G ; 1 user "-" (examples: A/- A/AGC or A/- GCA/A or -/A A/AGC or -/A AGC/A)
    else if(same(userA0,imputeA0) && userA1.equals("-"))
        {
        ret.setMessage("found indel. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+userA0+"/"+imputeA1);
        ret.setA0(userA0);
        ret.setA1(imputeA1);
        ret.setFlagEndOfLine("INDEL");
        return ret;
        }
    else if(same(userA0,imputeA1) && userA1.equals("-"))
        {
        ret.setMessage("found indel. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+userA0+"/"+imputeA0);
        ret.setA0(userA0);
        ret.setA1(imputeA0);
        ret.setFlagEndOfLine("INDEL");
        return ret;
        }
    else if(same(userA1,imputeA0) && userA0.equals("-"))
        {
        ret.setMessage("found indel. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+userA1+"/"+imputeA1);
        ret.setA0(userA1);
        ret.setA1(imputeA1);
        ret.setFlagEndOfLine("INDEL");
        return ret;
        }
    else if(same(userA1,imputeA1) && userA0.equals("-"))
        {
        ret.setMessage("found indel. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+userA1+"/"+imputeA0);
        ret.setA0(userA1);
        ret.setA1(imputeA0);
        ret.setFlagEndOfLine("INDEL");
        return ret;
        }
    // 1 antiparallele user/1000G ; 1 user "-" (examples: T/- A/AGC or T/- GCA/A or -/T A/AGC or -/T AGC/A)
    else if(antiparallele(userA0,imputeA0) && userA1.equals("-"))
        {
        ret.setMessage("found indel. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+imputeA0+"/"+imputeA1);
        ret.setA0(imputeA0);
        ret.setA1(imputeA1);
        ret.setFlagEndOfLine("INDEL");
        return ret;
        }
    else if(antiparallele(userA0,imputeA1) && userA1.equals("-"))
        {
        ret.setMessage("found indel. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+imputeA1+"/"+imputeA0);
        ret.setA0(imputeA1);
        ret.setA1(imputeA0);
        ret.setFlagEndOfLine("INDEL");
        return ret;
        }
    else if(antiparallele(userA1,imputeA0) && userA0.equals("-"))
        {
        ret.setMessage("found indel. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+imputeA1+"/"+imputeA0);
        ret.setA0(imputeA1);
        ret.setA1(imputeA0);
        ret.setFlagEndOfLine("INDEL");
        return ret;
        }
    else if(antiparallele(userA1,imputeA1) && userA0.equals("-"))
        {
        ret.setMessage("found indel. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+imputeA0+"/"+imputeA1);
        ret.setA0(imputeA0);
        ret.setA1(imputeA1);
        ret.setFlagEndOfLine("INDEL");
        return ret;
        }
    // 2 user "-"
    else if(userA0.equals("-") && userA1.equals("-"))
        {
        ret.setMessage("found indel. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+imputeA0+"/"+imputeA1);
        ret.setA0(imputeA0);
        ret.setA1(imputeA1);
        ret.setFlagEndOfLine("INDEL");
        return ret;
        }


    // example : AA AT
/*    else if(same(userA0,userA1) && !same(imputeA0,imputeA1))
        {
        ret.setMessage("data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+imputeA0+"/"+imputeA1);
        ret.setA0(imputeA0);
        ret.setA1(imputeA1);
        ret.setFlagEndOfLine("CHECK FREQUENCIES");
        return ret;
        }*/

    // 1 user 0 ; 1 user/1000G different(!same && !antiparallele)
    else if((((!same(userA0,imputeA0) && !antiparallele(userA0,imputeA0)) && (!same(userA0,imputeA1) && !antiparallele(userA0,imputeA1))) && userA1.equals("0")) || (((!same(userA1,imputeA0) && !antiparallele(userA1,imputeA0)) && (!same(userA1,imputeA1) && !antiparallele(userA1,imputeA1))) && userA0.equals("0")))
        {
        ret.setMessage("found 0-allele. data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+userA0+"/"+userA1);
        ret.setA0(userA0);
        ret.setA1(userA1);
        ret.setChromZero(true);
        ret.setFlagEndOfLine("INCOMPATIBLE_ALLELE");
        return ret;
        }

    else    {
        ret.setMessage("data:"+userA0+"/"+userA1+" vs impute:"+imputeA0+"/"+imputeA1+". keeping "+userA0+"/"+userA1);
        ret.setA0(userA0);
        ret.setA1(userA1);
        ret.setChromZero(true);
        ret.setFlagEndOfLine("INCOMPATIBLE_ALLELE");
        return ret;
        }

//    throw new IllegalArgumentException("Ce cas n'a pas ete étudié ! "+userA0+"/"+userA1+" vs "+imputeA0+"/"+imputeA1);
        }

    public static void main(String[] args) throws Exception {
     AllelesResolver app=new AllelesResolver();
       if(args.length==4)
    {
     Resolved r=app.resolve(args[0],args[1],args[2],args[3]);
    System.out.println(r.getA0()+" / "+r.getA1());
    if(r.getMessage()!=null) System.out.println("[LOG]"+r.getMessage());
    if(r.getFlagEndOfLine()!=null) System.out.println("[FLAG]"+r.getFlagEndOfLine());
    return;
    }
    else{
        String users[]=new String[]{"A","T","G","C","0","-"};
        String impute[]=new String[]{"A","T","G","C"};
        for(String a0:users)
            {
            for(String a1:users)
                {
                for(String a2:impute)
                    {

                    for(String a3:impute)
                        {
                        try
                        {
                         Resolved r=app.resolve(a0,a1,a2,a3);
                        System.out.println(r.getA0()+" / "+r.getA1());
                        if(r.getMessage()!=null) System.out.println("[LOG]"+r.getMessage());
                        if(r.getFlagEndOfLine()!=null) System.out.println("[FLAG]"+r.getFlagEndOfLine());
                        }catch(Exception err)
                        {
                        System.err.println("#FAILURE: "+a0+"/"+a1+" vs "+a2+"/"+a3);
                        }
                        }
                    }
                }
            }
        }
        }
    }


